package cn.edu.buaa.sei.jdat.vt;

import java.awt.geom.AffineTransform;
import java.util.ArrayList;

import cn.edu.buaa.sei.jdat.graph.DependencyGraph;
import cn.edu.buaa.sei.jdat.model.Jar;
import cn.edu.buaa.sei.jdat.vt.MainView.Tab;
import cn.edu.buaa.sei.jdat.vt.res.Resources;
import cn.edu.buaa.sei.jdat.vt.widgets.Button;
import cn.edu.buaa.sei.jdat.vt.widgets.CheckBox;
import cn.edu.buaa.sei.jdat.vt.widgets.JavaElementLabel;
import cn.edu.buaa.sei.jdat.vt.widgets.ListView;
import cn.edu.buaa.sei.jdat.vt.widgets.graph.GraphView;

import com.cocotingo.snail.Animation;
import com.cocotingo.snail.AnimationFunction;
import com.cocotingo.snail.GraphicsX;
import com.cocotingo.snail.MouseEvent;
import com.cocotingo.snail.View;
import com.cocotingo.snail.text.TextView;

public class DependencyView extends Tab {
	
	private class OptionView extends View {
		
		final ListView jarListView;
		final CheckBox chkUnknownPackages, chkExternalJars;
		
		public OptionView() {
			super(0, 0, 516, 400);
			setBackgroundColor(null);
			setPaintingEnabled(false);
			TextView label1;
			addSubview(label1 = new TextView(8, 8, 0, 0) {
				{
					setText("Select Jars:");
					setBackgroundColor(null);
					setFont(Resources.FONT_LABEL);
					setColor(Resources.COLOR_TEXT_DEFAULT);
					setSize(getPreferredSize());
				}
			});
			addSubview(jarListView = new ListView(8, 16 + label1.getHeight(), 250, 0));
			jarListView.setBottom(50);
			addSubview(new Button(8, 400 - 42, (250 - 8) / 2, 50 - 16) { // really bad numbers
				{
					setText("Select All");
				}
				@Override
				protected void buttonClicked(MouseEvent e) {
					for (View view : jarListView.getContentView()) {
						CheckBox checkBox = (CheckBox) view;
						checkBox.setSelected(true);
					}
				}
			});
			addSubview(new Button(16 + (250 - 8) / 2, 400 - 42, (250 - 8) / 2, 50 - 16) {
				{
					setText("Invert");
				}
				@Override
				protected void buttonClicked(MouseEvent e) {
					for (View view : jarListView.getContentView().getSubviews()) {
						CheckBox checkBox = (CheckBox) view;
						checkBox.setSelected(!checkBox.isSelected());
					}
				}
			});
			addSubview(new Button(250 + 16, 400 - 42, (250 - 8), 50 - 16) {
				{
					setText("Generate");
				}
				@Override
				protected void buttonClicked(MouseEvent e) {
					generateButtonClicked();
				}
			});
			addSubview(chkUnknownPackages = new CheckBox(0, 0, 0, 0) {
				{
					setLabelView(new TextView(0, 0, 0, 0) {
						{
							setText("Show Unknown Elements");
							setBackgroundColor(null);
							setFont(Resources.FONT_LABEL);
							setColor(Resources.COLOR_TEXT_DEFAULT);
							setSize(getPreferredSize());
						}
					});
					setSize(getPreferredSize());
					setSelected(true);
				}
			});
			addSubview(chkExternalJars = new CheckBox(0, 0, 0, 0) {
				{
					setLabelView(new TextView(0, 0, 0, 0) {
						{
							setText("Show External Dependency");
							setBackgroundColor(null);
							setFont(Resources.FONT_LABEL);
							setColor(Resources.COLOR_TEXT_DEFAULT);
							setSize(getPreferredSize());
						}
					});
					setSize(getPreferredSize());
					setSelected(true);
				}
			});
			chkExternalJars.setCenter(250 + 8 + 125, 0);
			chkExternalJars.setTop(400 - 50 - chkExternalJars.getHeight() - 8);
			chkUnknownPackages.setLeft(chkExternalJars.getLeft());
			chkUnknownPackages.setTop(chkExternalJars.getTop() - chkUnknownPackages.getHeight() - 8);
		}
		
		@Override
		protected void repaintView(GraphicsX g) {
			g.drawStrechableImage(Resources.IMG_DEPTH_BACKGROUND, getWidth(), getHeight());
		}
		
		Jar[] getSelectedJars() {
			ArrayList<Jar> jars = new ArrayList<Jar>();
			for (View view : jarListView.getContentView()) {
				CheckBox checkBox = (CheckBox) view;
				if (checkBox.isSelected()) {
					Jar jar = getOwner().getJarController().getJar(checkBox.getIndex());
					jars.add(jar);
				}
			}
			return jars.toArray(new Jar[0]);
		}
		
	}
	
	private final OptionView optionView;
	private final GraphView graphView;
	private final Button btnClose, btnGenerateReport;
	private int state;
	private static final int STATE_CONFIG = 0;
	private static final int STATE_BUSY = 1;
	private static final int STATE_READY = 2;

	public DependencyView(MainView owner) {
		super(owner);
		state = STATE_CONFIG;
		addSubview(graphView = new GraphView(0, 0, 0, 0) {
			{
				setHidden(true);
			}
		});
		addSubview(optionView = new OptionView());
		addSubview(btnClose = new Button(8, 8, 0, 0) {
			@Override
			protected void buttonClicked(MouseEvent e) {
				closeButtonClicked();
			}
		});
		btnClose.setText("Close");
		btnClose.setFont(Resources.FONT_LABEL);
		btnClose.setTextColor(Resources.COLOR_TEXT_DEFAULT);
		btnClose.setSize(btnClose.getPreferredSize());
		btnClose.setHidden(true);
		addSubview(btnGenerateReport = new Button(16 + btnClose.getWidth(), 8, 0, 0) {
			@Override
			protected void buttonClicked(MouseEvent e) {
				generateReportButtonClicked();
			}
		});
		btnGenerateReport.setText("Generate Report");
		btnGenerateReport.setFont(Resources.FONT_LABEL);
		btnGenerateReport.setTextColor(Resources.COLOR_TEXT_DEFAULT);
		btnGenerateReport.setSize(btnGenerateReport.getPreferredSize());
		btnGenerateReport.setHidden(true);
	}

	@Override
	protected void activated() {
		if (state == STATE_CONFIG) {
			optionView.jarListView.getContentView().removeAllSubviews();
			Jar[] jars = getOwner().getJarController().getAllJars();
			for (Jar jar : jars) {
				CheckBox checkBox = new CheckBox(0, 0, 0, 30) {
					@Override
					public View setSize(int width, int height) {
						super.setSize(width, height);
						if (getLabelView() != null) {
							getLabelView().setRight(0);
							getLabelView().setHeight(30);
						}
						return this;
					}
				};
				checkBox.setSelected(true);
				checkBox.setLabelView(new JavaElementLabel(jar));
				optionView.jarListView.getContentView().addSubview(checkBox);
			}
			optionView.jarListView.layout();
		}
	}

	@Override
	protected void deactivated() {
	}

	@Override
	protected void layout() {
		optionView.setCenter(getWidth() / 2, getHeight() / 2);
		graphView.setSize(getWidth(), getHeight());
		
		btnClose.setWidth(btnGenerateReport.getWidth());
		btnClose.setPosition(getWidth() / 2 - btnClose.getWidth() - 4, getHeight() - btnClose.getHeight());
		btnGenerateReport.setPosition(getWidth() / 2 + 4, btnClose.getTop());
	}
	
	private void generateButtonClicked() {

		new Animation(0.25f, AnimationFunction.EASE_OUT) {
			@Override
			protected void animation(float progress) {
				AffineTransform t = new AffineTransform();
				t.translate(optionView.getWidth() / 2, optionView.getHeight() / 2);
				t.scale(1.0f - progress / 2.0f, 1.0 - progress / 2.0f);
				t.translate(-optionView.getWidth() / 2, -optionView.getHeight() / 2);
				optionView.setTransform(t);
				optionView.setAlpha(1.0f - progress);
			}
			@Override
			protected void completed(boolean canceled) {
				optionView.setTransform(null);
				optionView.setHidden(true);
				optionView.setAlpha(1.0f);
			}
		}.commit();

		int opt = optionView.chkUnknownPackages.isSelected() ? DependencyGraph.OPT_UNKNOWN_PACKAGES : 0;
		opt |= optionView.chkExternalJars.isSelected() ? DependencyGraph.OPT_EXTERNAL_JARS : 0;
		DependencyGraph graph = getOwner().getJarController().generateGraph(optionView.getSelectedJars(), opt);
		
		state = STATE_BUSY;
		
		// show graph
		graphView.setGraph(graph, new Runnable() {
			@Override
			public void run() {
				// finished
				graphView.setHidden(false);
				btnClose.setHidden(false);
				btnGenerateReport.setHidden(false);
				state = STATE_READY;
			}
		});

	}
	
	private void closeButtonClicked() {
		graphView.setGraph(null, null);
		
		graphView.setHidden(true);
		btnClose.setHidden(true);
		btnGenerateReport.setHidden(true);
		
		state = STATE_CONFIG;
		
		optionView.setHidden(false);
		optionView.setAlpha(0.0f);
		new Animation(0.25f, AnimationFunction.EASE_OUT) {
			@Override
			protected void animation(float progress) {
				AffineTransform t = new AffineTransform();
				t.translate(optionView.getWidth() / 2, optionView.getHeight() / 2);
				t.scale(1.0f - (1.0f - progress) / 2.0f, 1.0 - (1.0f - progress) / 2.0f);
				t.translate(-optionView.getWidth() / 2, -optionView.getHeight() / 2);
				optionView.setTransform(t);
				optionView.setAlpha(1.0f - (1.0f - progress));
			}
			@Override
			protected void completed(boolean canceled) {
				optionView.setTransform(null);
				optionView.setAlpha(1.0f);
			}
		}.commit();
		
	}
	
	private void generateReportButtonClicked() {
		// TODO: generate report
	}

}
